home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / QuickDraw 3D / Samples / SampleCode / ScreenSaver / PICTSprite.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-14  |  12.2 KB  |  605 lines  |  [TEXT/CWIE]

  1. #include "PICTSprite.h"
  2. #include <QDOffscreen.h>
  3. #include <assert.h>
  4. #include <stdlib.h>
  5. #include "Q3ADUtilities.h"
  6.  
  7.  
  8.  
  9.  
  10. #if 0
  11. #pragma mark PRIVATE STRUCTURES
  12. #endif
  13.  
  14. typedef struct iPICTOffscreen
  15. {
  16.     long                    referenceCount;
  17.     long                    basePictureID;
  18.     long                    numFaces;
  19.     GWorldPtr                sourcePort;
  20.     Rect                    sourceRect;
  21.     
  22.     struct iPICTOffscreen    *nextOffscreen;
  23.     
  24. } iPICTOffscreen;
  25.  
  26.  
  27. typedef struct iTPICTSprite
  28. {
  29.     long            currentFace;
  30.     long            totalFaces;
  31.     iPICTOffscreen    *sourceOffscreen;
  32.     CGrafPtr        destPort;
  33.     Rect            destRect;
  34.     
  35. } iTPICTSprite;
  36.  
  37.     
  38. #if 0
  39. #pragma mark GLOBALS
  40. #endif
  41.  
  42. iPICTOffscreen    *gOffscreenHead    = NULL;
  43.  
  44.  
  45. #if 0
  46. #pragma mark PRIVATE FUNCTION DECLARATIONS
  47. #endif
  48.                 
  49. /*
  50. ** PRIVATE FUNCTIONS
  51. */
  52. static TQ3Status    iPICTSprite_ZeroOut(
  53.                         iTPICTSprite        *inSprite);
  54.  
  55.  
  56. static TQ3Status    iPICTOffscreen_ZeroOut(
  57.                         iPICTOffscreen        *inPICTOffscreen);
  58.                         
  59. static iPICTOffscreen *iPICTOffscreen_New(
  60.                 long        inNumFaces,
  61.                 long        inBasePictureID);
  62.  
  63. static TQ3Status    iPICTOffscreen_Draw(
  64.                         iPICTOffscreen *inPICTOffscreen,
  65.                         long            face,
  66.                         CGrafPtr        destPort,
  67.                         const Rect        *destRect
  68.                         );
  69.  
  70. static TQ3Status    iPICTOffscreen_Dispose(
  71.     iPICTOffscreen *ioPICTOffscreen);
  72.  
  73. static iPICTOffscreen    *iPICTOffscreen_Find(
  74.                             long inBasePictureID);
  75.  
  76.  
  77.  
  78. #if 0
  79. #pragma mark -
  80. #endif
  81.                 
  82. /******************************************************************************
  83.  **                                                                             **
  84.  **                        PUBLIC FUNCTION DEFINITIONS                             **
  85.  **                                                                             **
  86.  *****************************************************************************/
  87.  
  88. /*===========================================================================*\
  89.  *
  90.  *    Routine:    PICTSprite_New()
  91.  *
  92.  *    Comments:    
  93.  *
  94. \*===========================================================================*/
  95.  
  96. TPICTSprite *PICTSprite_New(
  97.                 long        inBasePictureID,
  98.                 long        inTotalFaces,
  99.                 long        inStartFace,
  100.                 CGrafPtr    inDestPort,
  101.                 Rect        *inDestRect)
  102. {
  103.     iTPICTSprite    *outPICTSprite    = NULL;
  104.     PicHandle        currentPicture    = NULL;
  105.     
  106.     TQ3Status        status = kQ3Success;
  107.     
  108.     assert(inDestPort);
  109.     
  110.     mBailIfNULL_(outPICTSprite = malloc(sizeof(iTPICTSprite)));
  111.     
  112.     iPICTSprite_ZeroOut(outPICTSprite);
  113.     
  114.     outPICTSprite->totalFaces        = inTotalFaces;
  115.     outPICTSprite->currentFace        = inStartFace;
  116.     outPICTSprite->destPort            = inDestPort;
  117.     outPICTSprite->destRect            = *inDestRect;
  118.  
  119.     mBailIfNULL_(outPICTSprite->sourceOffscreen    =
  120.                     iPICTOffscreen_New(inTotalFaces,inBasePictureID));
  121.  
  122.     return outPICTSprite;
  123.     
  124. bail:
  125.     if (outPICTSprite)
  126.         PICTSprite_Dispose(outPICTSprite);
  127.  
  128.     return NULL;
  129. }
  130.  
  131.  
  132. /*===========================================================================*\
  133.  *
  134.  *    Routine:    PICTSprite_Dispose()
  135.  *
  136.  *    Comments:    
  137.  *
  138. \*===========================================================================*/
  139.  
  140. TQ3Status    PICTSprite_Dispose(
  141.     TPICTSprite *ioSprite)
  142. {
  143.     assert(ioSprite);
  144.     
  145.     if (ioSprite->sourceOffscreen)
  146.         iPICTOffscreen_Dispose(ioSprite->sourceOffscreen);
  147.     
  148.     free(ioSprite);
  149.     
  150.     return kQ3Success;
  151. }
  152.  
  153.  
  154. /*===========================================================================*\
  155.  *
  156.  *    Routine:    PICTSprite_Draw()
  157.  *
  158.  *    Comments:    
  159.  *
  160. \*===========================================================================*/
  161.  
  162. TQ3Status    PICTSprite_Draw(
  163.                 TPICTSprite *inSprite)
  164. {
  165.     TQ3Status    status = kQ3Success;
  166.     
  167.     inSprite->currentFace    =
  168.         (inSprite->currentFace + 1) % inSprite->totalFaces;
  169.         
  170.     status    =    iPICTOffscreen_Draw(
  171.                     inSprite->sourceOffscreen,
  172.                     inSprite->currentFace,
  173.                     inSprite->destPort,
  174.                     &inSprite->destRect);
  175.  
  176.     return status;
  177. }
  178.  
  179.  
  180.  
  181. #if 0
  182. #pragma mark -
  183. #endif
  184.  
  185. /******************************************************************************
  186.  **                                                                             **
  187.  **                        PRIVATE FUNCTION DEFINITIONS                         **
  188.  **                                                                             **
  189.  *****************************************************************************/
  190.  
  191. /*===========================================================================*\
  192.  *
  193.  *    Routine:    iPICTSprite_ZeroOut()
  194.  *
  195.  *    Comments:    
  196.  *
  197. \*===========================================================================*/
  198.  
  199. static TQ3Status iPICTSprite_ZeroOut(
  200.                     iTPICTSprite *inSprite)
  201. {
  202.     assert(inSprite);
  203.         
  204.     inSprite->currentFace        = 0;
  205.     inSprite->totalFaces        = 0;
  206.     inSprite->sourceOffscreen    = NULL;
  207.     
  208.     inSprite->destPort            = NULL;
  209.     
  210.     inSprite->destRect.top        =
  211.     inSprite->destRect.bottom    =
  212.     inSprite->destRect.left        =
  213.     inSprite->destRect.right    = 0;
  214.     
  215.     return kQ3Success;
  216. }
  217.  
  218.  
  219. /*===========================================================================*\
  220.  *
  221.  *    Routine:    iPICTOffscreen_ZeroOut()
  222.  *
  223.  *    Comments:    
  224.  *
  225. \*===========================================================================*/
  226.  
  227. static TQ3Status iPICTOffscreen_ZeroOut(
  228.                     iPICTOffscreen *inPICTOffscreen)
  229. {
  230.     assert(inPICTOffscreen);
  231.         
  232.     inPICTOffscreen->referenceCount    = 0;
  233.     inPICTOffscreen->basePictureID    = 0;
  234.     inPICTOffscreen->numFaces        = 0;
  235.     inPICTOffscreen->sourcePort        = NULL;
  236.     
  237.     inPICTOffscreen->sourceRect.top        =
  238.     inPICTOffscreen->sourceRect.bottom    =
  239.     inPICTOffscreen->sourceRect.left    =
  240.     inPICTOffscreen->sourceRect.right    = 0;
  241.     
  242.     inPICTOffscreen->nextOffscreen    = NULL;
  243.     
  244.     return kQ3Success;
  245. }
  246.  
  247. /*===========================================================================*\
  248.  *
  249.  *    Routine:    iPICTOffscreen_New()
  250.  *
  251.  *    Comments:    
  252.  *
  253. \*===========================================================================*/
  254.  
  255. static iPICTOffscreen *iPICTOffscreen_New(
  256.                 long        inNumFaces,
  257.                 long        inBasePictureID)
  258. {
  259.  
  260.     iPICTOffscreen    *outPICTOffscreen    = NULL;
  261.     PicHandle        currentPicture        = NULL;
  262.     Rect            gworldRect;
  263.     
  264.     TQ3Status        status = kQ3Success;
  265.  
  266.     
  267.     /*
  268.     **    Check to see if we've already loaded these pictures before (we use
  269.     **    the base ID as our check).
  270.     */
  271.     
  272.     outPICTOffscreen = iPICTOffscreen_Find(inBasePictureID);
  273.     
  274.     /*
  275.     **    If we find one, we return it.
  276.     */
  277.     
  278.     if (outPICTOffscreen)
  279.         return outPICTOffscreen;
  280.  
  281.     /*
  282.     **    Apparently, this one uses different pictures than others that we
  283.     **    have loaded. So, we build a new one.
  284.     */
  285.     
  286.     mBailIfNULL_(outPICTOffscreen = malloc(sizeof(iPICTOffscreen)));
  287.     
  288.  
  289.     iPICTOffscreen_ZeroOut(outPICTOffscreen);
  290.     
  291.     outPICTOffscreen->basePictureID    = inBasePictureID;
  292.     outPICTOffscreen->numFaces        = inNumFaces;
  293.     
  294.     
  295.     /*
  296.     **    In order to determine how large of a GWorld to create to store
  297.     **  all of our pictures, we need to grab the first one to get the rect
  298.     **
  299.     **  NOTE: We are assuming that ALL THE PICTURES ARE THE SAME SIZE!!!
  300.     */
  301.     
  302.     
  303.     mBailIfNULL_(currentPicture    =    GetPicture(outPICTOffscreen->basePictureID));
  304.  
  305.     /*
  306.     **    Our GWorld rect is going to be very long and horizontal.
  307.     **    each face of the sprite is stored in it so we make it
  308.     **    as wide as our picture * the number of faces
  309.     */
  310.     
  311.     outPICTOffscreen->sourceRect.top        =
  312.     outPICTOffscreen->sourceRect.left        = 0;
  313.     outPICTOffscreen->sourceRect.right        =     (**currentPicture).picFrame.right;
  314.     outPICTOffscreen->sourceRect.bottom        = (**currentPicture).picFrame.bottom;
  315.     
  316.     gworldRect.top                        =
  317.     gworldRect.left                        = 0;
  318.     gworldRect.right                    =     ((**currentPicture).picFrame.right *
  319.                                             outPICTOffscreen->numFaces);
  320.     gworldRect.bottom                    = (**currentPicture).picFrame.bottom;
  321.  
  322.     /*
  323.     **    We got what we needed, so let's get rid of it
  324.     */
  325.     ReleaseResource((Handle)currentPicture);
  326.     currentPicture    =    NULL;
  327.  
  328.     /*
  329.     **    Allocate it
  330.     */
  331.     if (NewGWorld(
  332.             &outPICTOffscreen->sourcePort,
  333.             16,
  334.             &gworldRect,
  335.             NULL,
  336.             NULL,
  337.             useTempMem)        == noErr)
  338.  
  339.     {
  340.         PixMapHandle     hPixMap;
  341.         CGrafPtr        savedPort;
  342.         GDHandle        savedGDevice;
  343.         
  344.         GetGWorld(&savedPort, &savedGDevice);
  345.         SetGWorld(outPICTOffscreen->sourcePort, NULL);
  346.         
  347.         EraseRect(&outPICTOffscreen->sourcePort->portRect);
  348.         
  349.         SetGWorld(savedPort, savedGDevice);
  350.  
  351.         hPixMap = GetGWorldPixMap (outPICTOffscreen->sourcePort);
  352.         HLock ((Handle) hPixMap);
  353.         LockPixels (hPixMap);
  354.         
  355.     } else {
  356.         status = kQ3Failure;
  357.         goto bail;
  358.     }
  359.     
  360.     
  361.     /*
  362.     **    Now, we fill it up with pictures
  363.     */
  364.     
  365.  
  366.     {
  367.         long i = 0;
  368.         GWorldPtr    savedGWorld;
  369.         GDHandle    savedGDevice;
  370.         
  371.         GetGWorld(&savedGWorld, &savedGDevice);
  372.         SetGWorld(outPICTOffscreen->sourcePort, NULL);
  373.         
  374.         /*
  375.         **    INV:    Port is changed
  376.         */
  377.         
  378.         for (i = 0; i < outPICTOffscreen->numFaces; i++)
  379.         {
  380.             Rect    picDestRect;
  381.             
  382.             if ((currentPicture    =
  383.                             GetPicture(outPICTOffscreen->basePictureID + i)) == NULL)
  384.             {
  385.                 SetGWorld(savedGWorld, savedGDevice);
  386.                 /*
  387.                 **    INV:    Port is reset
  388.                 */
  389.  
  390.                 goto bail;
  391.             }
  392.                             
  393.             picDestRect    = (**currentPicture).picFrame;
  394.             OffsetRect(&picDestRect, i * picDestRect.right, 0);
  395.             DrawPicture(currentPicture, &picDestRect);
  396.             
  397.             ReleaseResource((Handle)currentPicture);
  398.             currentPicture    =    NULL;
  399.             
  400.         }    /*    for all faces    */
  401.         
  402.         SetGWorld(savedGWorld, savedGDevice);
  403.         /*
  404.         **    INV:    Port is reset
  405.         */
  406.     
  407.     }
  408.  
  409.     return outPICTOffscreen;
  410.  
  411. bail:
  412.  
  413.     if (outPICTOffscreen)
  414.         iPICTOffscreen_Dispose(outPICTOffscreen);
  415.         
  416.     if (currentPicture)
  417.         ReleaseResource((Handle)currentPicture);
  418.         
  419.     return NULL;
  420. }
  421.  
  422.  
  423. /*===========================================================================*\
  424.  *
  425.  *    Routine:    iPICTOffscreen_Draw()
  426.  *
  427.  *    Comments:    
  428.  *
  429. \*===========================================================================*/
  430.  
  431. static TQ3Status    iPICTOffscreen_Draw(
  432.                         iPICTOffscreen *inPICTOffscreen,
  433.                         long            face,
  434.                         CGrafPtr        destPort,
  435.                         const Rect        *destRect
  436.                         )
  437. {
  438.     TQ3Status    status = kQ3Success;
  439.  
  440.     assert(inPICTOffscreen);
  441.     assert(destPort);
  442.     
  443.     {
  444.         /*
  445.         **    Sorry this is so ugly.
  446.         */
  447.         
  448.         
  449.         Rect    offsetRect    = inPICTOffscreen->sourceRect;
  450.         
  451.         /*
  452.         **    we have to save the last port
  453.         */
  454.         GWorldPtr        savedPort;
  455.         GDHandle        tempGDHandle;
  456.         
  457.         /*
  458.         **    These are used for *one* call, that being the one to CopyBits
  459.         **    setting up the environment just so, will allow the fastest
  460.         **    blitting
  461.         */
  462.         
  463.         RGBColor        savedForeground,
  464.                         savedBackground;
  465.         RGBColor        white                = {0xFFFF, 0xFFFF, 0xFFFF};
  466.         RGBColor         black                = {0, 0, 0};
  467.         PixMapHandle     offscreenBitmap        = NULL;
  468.         PixMapHandle     destBitmap            = NULL;
  469.  
  470.         OffsetRect(&offsetRect, offsetRect.right * face, 0);
  471.         
  472.         /*
  473.         **    save off the port
  474.         */
  475.         GetGWorld((GWorldPtr*)&savedPort, &tempGDHandle);
  476.         
  477.         /*
  478.         **    now, we get ready to CopyBits. There is some setup to make it
  479.         **    fast, so we do that first.
  480.         */
  481.         GetForeColor (&savedForeground);
  482.         GetBackColor (&savedBackground);
  483.         
  484.         RGBForeColor (&black);
  485.         RGBBackColor (&white);
  486.  
  487.         /*
  488.         **    Grab the source and destination pixmaps
  489.         */
  490.         destBitmap = GetGWorldPixMap (destPort);
  491.         offscreenBitmap = GetGWorldPixMap (inPICTOffscreen->sourcePort);
  492.  
  493.         /*
  494.         **    Now for God knows why, we have to set the GWorld to the
  495.         **    *destination* of our CopyBits or prepare to Restart.
  496.         */
  497.         SetPort((GrafPort *)destPort);
  498.         
  499.         
  500.         /*
  501.         **    Again, for God knows why, we have to do a PenNormal here
  502.         **    or CopyBits works weird.
  503.         */
  504.         PenNormal();
  505.         
  506.         /*
  507.         **    do it.
  508.         **    BTW, we use the fOffscreen->portRect twice because it's
  509.         **    at 0,0 and that's what we want.
  510.         */
  511.         
  512.         CopyBits ((const struct BitMap *)*offscreenBitmap,
  513.                   (const struct BitMap *)*destBitmap,
  514.                   &offsetRect, 
  515.                   destRect,
  516.                   srcCopy | ditherCopy, 0L);
  517.         
  518.         /*
  519.         **    Restore all that stuff
  520.         */
  521.         RGBForeColor (&savedForeground);
  522.         RGBBackColor (&savedBackground);
  523.         
  524.         /*
  525.         **    We can't forget to restore our original port
  526.         */
  527.         SetGWorld((CGrafPtr)savedPort, tempGDHandle);
  528.         
  529.     }
  530.  
  531.     return status;
  532. }
  533.  
  534.  
  535. /*===========================================================================*\
  536.  *
  537.  *    Routine:    iPICTOffscreen_Dispose()
  538.  *
  539.  *    Comments:    
  540.  *
  541. \*===========================================================================*/
  542.  
  543. static TQ3Status    iPICTOffscreen_Dispose(
  544.     iPICTOffscreen *ioPICTOffscreen)
  545. {
  546.  
  547.     assert(ioPICTOffscreen);
  548.     
  549.     if (ioPICTOffscreen->referenceCount > 1)
  550.     {
  551.         ioPICTOffscreen->referenceCount++;
  552.         
  553.         return kQ3Success;
  554.     }
  555.     
  556.     else {
  557.     
  558.         if (ioPICTOffscreen->sourcePort)
  559.         {
  560.             PixMapHandle     hPixMap;
  561.             
  562.             hPixMap = GetGWorldPixMap (ioPICTOffscreen->sourcePort);
  563.  
  564.             HUnlock ((Handle) hPixMap);
  565.             UnlockPixels (hPixMap);
  566.             
  567.             DisposeGWorld (ioPICTOffscreen->sourcePort);
  568.         }
  569.         
  570.         free(ioPICTOffscreen);
  571.         
  572.     }
  573.     
  574.     return kQ3Success;
  575. }
  576.  
  577.  
  578. /*===========================================================================*\
  579.  *
  580.  *    Routine:    iPICTOffscreen_Find()
  581.  *
  582.  *    Comments:    
  583.  *
  584. \*===========================================================================*/
  585.  
  586. static iPICTOffscreen    *iPICTOffscreen_Find(
  587.                             long inBasePictureID)
  588. {
  589.     iPICTOffscreen *iterator = gOffscreenHead;
  590.     long    done = false;
  591.     
  592.     while ((iterator != NULL) && !done)
  593.     {
  594.         if (inBasePictureID == iterator->basePictureID)
  595.             done = true;
  596.         else
  597.             iterator = iterator->nextOffscreen;
  598.     }
  599.     
  600.     return iterator;
  601.     
  602. }
  603.  
  604.  
  605.